﻿using Rw.Core.Redis;
using Rw.Core.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WH.Common.Cache
{
    public class RedisCaching : ICaching
    {
        private readonly IRedisService _redisService;

        private const int default_cache_duration_value = 7200;

        public RedisCaching(IRedisService redisService)
        {
            _redisService = redisService;
        }

        public void Add<V>(string key, V value, TimeSpan cacheDurationInTimeSpan)
        {
            _redisService.CSRedis.Set(key, value, cacheDurationInTimeSpan);
        }

        public void Add<V>(string key, V value)
        {
            _redisService.CSRedis.Set(key, value);
        }

        public void Add<V>(string key, V value, int cacheDurationInSeconds = default_cache_duration_value)
        {
            _redisService.CSRedis.Set(key, value, cacheDurationInSeconds);
        }

        public bool ContainsKey<V>(string key)
        {
            return _redisService.CSRedis.Exists(key);
        }

        public void ContainsRemove(string keyStr)
        {
            var keyList = GetAllKey(keyStr);

            foreach (var key in keyList)
            {
                Remove(key);
            }
        }

        public V Get<V>(string key)
        {
            return _redisService.CSRedis.Get<V>(key);
        }

        public IEnumerable<string> GetAllKey(string key = "")
        {
            var list = new List<string>();

            // 开始迭代游标
            long cursor = 0;
            const int pageSize = 100;  // 每次迭代取出的 key 数量

            do
            {
                // 使用 SCAN 命令获取一批 key
                var result = _redisService.CSRedis.Scan(cursor, $"*{key}*", pageSize);

                // 解析返回结果
                cursor = result.Cursor;
                var keys = result.Items;

                // 处理当前批次的 keys
                list.AddRange(keys);

            } while (cursor != 0);

            return list;

            //return _redisService.CSRedis.Keys($"*{key}*");
        }

        public IEnumerable<string> GetAllKey<V>()
        {
            return GetAllKey();
        }

        public V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = default_cache_duration_value)
        {
            if (this.ContainsKey<V>(cacheKey))
            {
                var result = this.Get<V>(cacheKey);
                if (result == null)
                {
                    return create();
                }
                else
                {
                    return result;
                }
            }
            else
            {
                var result = create();
                this.Add(cacheKey, result, cacheDurationInSeconds == int.MaxValue ? default_cache_duration_value : cacheDurationInSeconds);
                return result;
            }
        }

        public string Info()
        {
            throw new NotImplementedException();
        }

        public void Remove(string key)
        {
            _redisService.CSRedis.Del(key);
        }

        public void Remove<V>(string key)
        {
            _redisService.CSRedis.Del(key);
        }

        public async Task<bool> HMSetAsync<V>(string key, IDictionary<string, V> value)
        {
            var resAdd = await _redisService.CSRedis.HMSetAsync(key, value.SelectMany(x => { return new object?[] { x.Key, x.Value }; }).ToArray());
            var resExp = await _redisService.CSRedis.ExpireAsync(key, default_cache_duration_value);
            return resAdd && resExp;
        }

        public async Task<Dictionary<string, V>> HGetAllAsync<V>(string key)
        {
            return await _redisService.CSRedis.HGetAllAsync<V>(key);
        }

        public async Task<V?> HGetAsync<V>(string key, string field)
        {
            return await _redisService.CSRedis.HGetAsync<V>(key, field);
        }

    }
}
